#include "Blo_Flower_ss.h"

HDC				hDC=NULL;			// Private GDI Device Context
HGLRC			hRC=NULL;			// Permanent Rendering Context
HWND			hWnd=NULL;			// Holds Our Window Handle
HINSTANCE		hInstance;			// Holds The Instance Of The Application

DEVMODE			DMsaved;			// Saves the previous screen settings
UINT			uTimer;				// timer identifier

int width;
int height;

GLFont		*fontarial;

// User Defined Variables
long double		angle;
long double		curTime, lastTickCount, realt, t;

Lines lights;

static __int64 timerstart;
static __int64 timerfrq;

void panInitTimer() {
	QueryPerformanceCounter((LARGE_INTEGER *)&timerstart);
	QueryPerformanceFrequency((LARGE_INTEGER *)&timerfrq);
}

double panGetTime() {
  __int64 a;
	QueryPerformanceCounter((LARGE_INTEGER *)&a);
	
	return (double)(a - timerstart)/(double)(timerfrq);
}

class Vector3
{
public:
	float x, y, z, r;
	Vector3(float a, float b, float c)
	{
		x = a;
		y = b;
		z = c;
	}
	Vector3()
	{
	}	
};

Vector3 petal[27][161];

void ViewOrtho()												// Set Up An Ortho View
{
	glMatrixMode(GL_PROJECTION);								// Select Projection
	glPushMatrix(); 											// Push The Matrix
	glLoadIdentity();											// Reset The Matrix
	glOrtho( 0, width, height, 0, -1, 1);						// Select Ortho Mode (WIDTHxHEIGHT)
	glMatrixMode(GL_MODELVIEW); 								// Select Modelview Matrix
	glPushMatrix(); 											// Push The Matrix
	glLoadIdentity();											// Reset The Matrix
}

void ViewPerspective()											// Set Up A Perspective View
{
	glMatrixMode( GL_PROJECTION );								// Select Projection
	glPopMatrix();												// Pop The Matrix
	glMatrixMode( GL_MODELVIEW );								// Select Modelview
	glPopMatrix();												// Pop The Matrix
}

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize And Initialize The GL Window
{
	glViewport (0, 0, (GLsizei)(width), (GLsizei)(height));				// Reset The Current Viewport
	glMatrixMode (GL_PROJECTION);										// Select The Projection Matrix
	glLoadIdentity ();													// Reset The Projection Matrix
	gluPerspective(50, (float)width/(float)height, 5,  2000);
	glMatrixMode (GL_MODELVIEW);										// Select The Modelview Matrix
	glLoadIdentity ();													// Reset The Modelview Matrix
}

int InitGL(GLvoid)												// All Setup For OpenGL Goes Here
{
	double r, p4, p8, phi;
	Vector3 p;

	lastTickCount = GetTickCount();
	curTime = 73500.f;

	glViewport(0 , 0, width, height);							// Set Up A Viewport
	glMatrixMode(GL_PROJECTION);								// Select The Projection Matrix
	glLoadIdentity();											// Reset The Projection Matrix
	gluPerspective(50, (float)width/(float)height, 0,  2000);	// Set Our Perspective
	glMatrixMode(GL_MODELVIEW); 								// Select The Modelview Matrix
	glLoadIdentity();											// Reset The Modelview Matrix
	
	glEnable(GL_DEPTH_TEST);									// Enable Depth Testing
		
	glShadeModel(GL_SMOOTH);									// Select Smooth Shading

	glEnable(GL_POLYGON_SMOOTH);
	glEnable(GL_LINE_SMOOTH);
//  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);

	glMateriali(GL_FRONT, GL_SHININESS, 128);
	glClearColor(0.0f, 0.0f, 0.0f, 0.5);						// Set The Clear Color To Black
		
	fontarial = new GLFont(hDC, "Arial");

	for (int j = 0; j <= 26; j++)
	{
		for (int i = 0; i <= 160; i++)
		{
			phi = i * 21.0f * PI / N;
			p4 = sin(17 * phi / 3);
			p8 = sin(2 * cos(3 * phi) - 28 * phi);
			r = (1 - j * 0.038) * 5 * (1 + sin(11 * phi / 5)) - 4*p4*p4*p4*p4 * p8*p8*p8*p8*p8*p8*p8*p8;
			
			p.x = (float) (r * cos(phi));
			p.y = (float) (r * sin(phi));
			p.z = (float) (r * r * j * 0.02);

			petal[j][i].r = (float) r;
			petal[j][i].x = (float) (r * cos(phi));
			petal[j][i].y = (float) (r * sin(phi));
			petal[j][i].z = (float) (r * r * j * 0.02);
		}
	}

	panInitTimer();
	lights.Init();
	return TRUE;												// Return TRUE (Initialization Successful)
}

int DrawGLScene(GLvoid)
{

	static int len, i, j;
	static Vector3 p;
	static double r;
	static float R, G, B;
	
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear Screen And Depth Buffer

	glLoadIdentity();											// Reset The View	
		
	glPushMatrix();
	
	glTranslatef(2, 2, -.2f);
	glEnable(GL_BLEND);
	glDisable(GL_DEPTH_TEST);
	lights.RenderFrame(realt);
	glPopMatrix();

	glLoadIdentity();											
	
	glPushMatrix();
	
	glTranslatef(0, 2, -30);

	glRotatef(376.0f, 0, 1, 0);
	glRotatef(335.0f, 1, 0, 0);

	glDisable(GL_BLEND);
	glDisable(GL_DEPTH_TEST);
	
	glRotatef(angle, 0, 0, 1);
	for (j = 0; j <= 26; j++)
	{
		glRotatef(16.4f * j, 0, 0, 1);
		glBegin(GL_POLYGON);
		for (i = 0; i <= 160; i++)
		{
			// generate QUAD color
			R = 0.1 + (0.3 * sin(curTime/2800 - petal[j][i].r/2.5));
			G = 0.1 + (0.3 * sin(curTime/1900 - petal[j][i].r/2));
			B = 0.1 + (0.3 * cos(curTime/2400 - petal[j][i].r/3));
			glColor4f(R, G, B, 0.8);
			glVertex3f(petal[j][i].x, petal[j][i].y, petal[j][i].z);
		}
		glEnd();
		glLineWidth(0.5f);
		glBegin(GL_LINE_STRIP);
		for (i = 0; i <= 160; i += 6)
		{
			R = 0.4 + (0.3 * sin(curTime/2800 - petal[j][i].r/2.5));
			G = 0.4 + (0.3 * sin(curTime/1900 - petal[j][i].r/2));
			B = 0.4 + (0.3 * cos(curTime/2400 - petal[j][i].r/3));

			glColor4f(R, G, B, r);
			glVertex3f(petal[j][i].x, petal[j][i].y, petal[j][i].z);
		}
		glEnd();
	}

	glPopMatrix();
	
	ViewOrtho();

	CoolPrint1(*fontarial, 4, t, 1.5f, 3.0f, 8.0f, 10.0f, width / 1.905, height * 0.73, 0.12 * width, 2.f, 0.5f, "Peace");
	CoolPrint1(*fontarial, 6, 10-t, -1.0f, 1.0f, 5.0f, 7.0f, width/2, height * 0.9, 0.097 * width, 0.6f, 0.2f, "all over the world");
	
	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
	
	ViewPerspective();											// Switch To A Perspective View
	
	glFlush ();													// Flush The GL Rendering Pipeline	
	
	return 0;
}

GLvoid KillGLWindow(GLvoid)								// Properly Kill The Window
{
	if (hRC)											// Do We Have A Rendering Context?
	{
		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
		{
			MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
		{
			MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}
		hRC=NULL;										// Set RC To NULL
	}

	if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC
	{
		MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hDC=NULL;										// Set DC To NULL
	}
}

/************************************************************************************/

/*	This Code Creates Our OpenGL Window.  Parameters Are:					*
 *	title			- Title To Appear At The Top Of The Window				*
 *	width			- Width Of The GL Window Or Fullscreen Mode				*
 *	height			- Height Of The GL Window Or Fullscreen Mode			*
 *	bits			- Number Of Bits To Use For Color (8/16/24/32)			*
 *	fullscreenflag	- Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE)	*/
 
BOOL CreateGLWindow(HWND hWnd, int bits)
{
	GLuint		PixelFormat;			// Holds The Results After Searching For A Match
	RECT		WindowRect;				// Grabs Rectangle Upper Left / Lower Right Values

	hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window

	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DMsaved); // save the current display state (NEW)

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		bits,										// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		32,											// 16Bit Z-Buffer (Depth Buffer)  
		0,											// No Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};
	
	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

    GetClientRect (hWnd, &WindowRect); 
	
	width = WindowRect.right - WindowRect.left;
	height = WindowRect.bottom - WindowRect.top;
	ReSizeGLScene(width, height);					// Set Up Our Perspective GL Screen


    if (!InitGL())									// Initialize Our Newly Created GL Window
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	return TRUE;									// Success
}

LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT message, 
					 WPARAM wParam, LPARAM lParam) 
{
	switch (message)									// Check For Windows Messages
	{
        case WM_CREATE:
		{
			if (!CreateGLWindow(hWnd,16))
			{
				return -1;									
			}
            uTimer = SetTimer(hWnd, 1, 10, NULL); 
			return 0;
		}

        case WM_TIMER: 

			angle += ((float)(GetTickCount() - lastTickCount) / 150.0f);	// Update angle Based On The Clock	
			if (angle > 360)
				angle -= 360;
			curTime += (float) (GetTickCount() - lastTickCount);
			lastTickCount = GetTickCount();
			realt = static_cast<float>(panGetTime());
			t = fmodf(realt, 12.f);

			DrawGLScene();                      
			SwapBuffers(hDC);					
			break;

        case WM_DESTROY: 
            if (uTimer) 
                KillTimer(hWnd, uTimer); 
			KillGLWindow();									
            break; 
	}

	// Pass All Unhandled Messages To DefScreenSaverProc
    return DefScreenSaverProc(hWnd, message, wParam, lParam); 
}

BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT message, 
								WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_INITDIALOG:
		return TRUE;
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
			EndDialog(hDlg, TRUE);
			return TRUE;
		}
	}

	return FALSE;
}

BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
	return TRUE;
}

